Reasons for Redundant AsQueryable() Calls When Upgrading to .NET 6
TLDR
- Residual
AsQueryable()calls in legacy .NET Core projects were often used to resolve conflicts betweenIQueryableandIAsyncEnumerableextension methods. - When both
System.Linq.Asyncand older versions of EF Core are installed, the compiler encounters ambiguity because it cannot determine whetherWhere()orSelect()should apply to theIQueryableorIAsyncEnumerableinterface. - After upgrading to EF Core 6,
DbSetno longer directly implementsIAsyncEnumerable, making it safe to remove redundantAsQueryable()calls.
Analysis of Extension Method Conflicts
When this issue occurs: When a project references the System.Linq.Async package and uses EF Core 5 or earlier.
Prior to EF Core 5, DbSet<TEntity> implemented both IQueryable<TEntity> and IAsyncEnumerable<TEntity> interfaces:
public abstract class DbSet<TEntity> :
Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<IServiceProvider>,
System.Collections.Generic.IAsyncEnumerable<TEntity>,
System.Collections.Generic.IEnumerable<TEntity>,
System.ComponentModel.IListSource,
System.Linq.IQueryable<TEntity> where TEntity : classIn this scenario, the AsyncEnumerable extension methods provided by System.Linq.Async conflict with the Queryable extension methods (such as Where and Select) provided by System.Linq. The compiler cannot determine whether the developer intends to call the synchronous IQueryable extension method or the asynchronous IAsyncEnumerable extension method. To explicitly specify the type, developers had to call AsQueryable() explicitly.
Improvements in EF Core 6
When you can remove AsQueryable(): When the project has been upgraded to EF Core 6 or higher.
In EF Core 6, the interface implementation of DbSet<TEntity> has been adjusted, removing the direct implementation of IAsyncEnumerable<TEntity>:
public abstract class DbSet<TEntity> :
Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<IServiceProvider>,
System.Collections.Generic.IEnumerable<TEntity>,
System.ComponentModel.IListSource,
System.Linq.IQueryable<TEntity> where TEntity : classDue to the change in interface definition, the compiler no longer faces ambiguity in choosing extension methods. Therefore, even if System.Linq.Async is still installed in the project, conflicts will no longer occur, and developers can safely remove redundant AsQueryable() calls from the code.
Change Log
- 2024-07-16 Initial documentation created.
